package com.blue.crawler.download;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.concurrent.atomic.AtomicInteger;

import com.blue.crawler.model.FileModel;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.blue.core.dict.UploadType;
import com.blue.core.id.UUID;
import com.blue.core.util.NumberUtil;
import com.blue.core.util.PhotoUtil;
import com.blue.core.util.UrlUtil;
import com.blue.crawler.annotation.CrawlerConfig;
import com.blue.crawler.util.CrawlerInvoker;


public class FileDownload implements Download
{
	private static Logger logger = LoggerFactory.getLogger(FileDownload.class);
	
	private final String root;
	private final Type type;
	private final AtomicInteger counter;
	
	public FileDownload(String root)
	{
		this(root, Type.DATE);
	}
	
	public FileDownload(String root, Type type)
	{
		this.root = root;
		this.type = type;
		this.counter = new AtomicInteger(1);
	}

	@Override
	public FileModel download(FileModel model, CrawlerConfig config)
	{
		/*String root = this.root;
		if (config.getRoot() != null && !config.getRoot().isEmpty())
			root = config.getRoot();*/
		
		FileModel fileModel = this.getFileModel(model);
		
		for (int i = 0; i < config.getRetry(); i++)
		{
			try
			{
				this.download(config, fileModel);
				break;
			}
			catch (Exception e)
			{
				logger.error("下载失败，第 {} 次重试，{} 秒后继续下载，URL：{}", i+1, config.getInterval(), fileModel.getUrl());
				if (config.getInterval() > 0)
				{
					try
					{
						Thread.sleep(config.getInterval() * 1000);
					}
					catch (InterruptedException e1)
					{
						e1.printStackTrace();
					}
				}
			}
		}

		
		return fileModel;
	}
	
	
	protected void download(CrawlerConfig config, FileModel fileModel) throws IOException
	{
		HttpURLConnection conn = null;
		try
		{
			URL u = new URL(fileModel.getUrl());
			if (config.isProxy())
			{
				InetSocketAddress addr = new InetSocketAddress(config.getProxyHost(), config.getProxyPort());
				Proxy proxy = new Proxy(config.getProxyType(), addr);
				conn = (HttpURLConnection)u.openConnection(proxy);
			} 
			else
			{
				conn = (HttpURLConnection)u.openConnection();
			}
			
			conn.setConnectTimeout(CrawlerInvoker.TIMEOUT);
			conn.setReadTimeout(CrawlerInvoker.TIMEOUT);
			conn.setRequestProperty("Referer", fileModel.getReferer());
			conn.setRequestProperty("User-Agent", CrawlerInvoker.USER_AGENT);
			conn.setRequestProperty("Host", UrlUtil.getHost(fileModel.getUrl()));
			fileModel.setSize(conn.getContentLength());
			fileModel.setMimeType(conn.getContentType());
			fileModel.setType(UploadType.getType(fileModel.getMimeType(), fileModel.getName()));
			
			try (InputStream is = conn.getInputStream();
					OutputStream os = new FileOutputStream(root + fileModel.getPath()))
			{
				IOUtils.copyLarge(is, os);
			}
			
			File file = new File(root + fileModel.getPath());
			fileModel.setSize((int)file.length());
			
			if (fileModel.getType() == UploadType.PIC) // 是图片才缩小
			{
				int thumbWidth = config.getThumbWidth();
				int thumbHeight = config.getThumbHeight();
				try
				{
					PhotoUtil.thumbCenter(file, new File(root + fileModel.getThumbPath()), thumbWidth, thumbHeight);
				}
				catch (IllegalArgumentException e)
				{
					logger.error("无法缩放图片：" + fileModel.getThumbPath(), e);
				}
			}
			else
			{
				fileModel.setThumbPath(null);
			}

			logger.info("下载：{}，大小：{}", fileModel.getUrl(), NumberUtil.byteFormat(fileModel.getSize()));
		}
		finally
		{
			if (conn != null)
			{
				conn.disconnect();
			}
		}
	}
	
	protected FileModel getFileModel(FileModel model)
	{
		if (model.getCreateTime() == null)
			model.setCreateTime(LocalDateTime.now());
		
		String ext = UrlUtil.getFileExt(model.getUrl());
		StringBuilder fileName = new StringBuilder();
		fileName.append("/upload");
		if (type == Type.DATE)
		{
			fileName.append(model.getCreateTime().format(Download.UPLOAD_PATTERN));
		}
		else if (type == Type.DOC)
		{
			fileName.append("/").append(counter.getAndIncrement()).append("/");
		}
		File dir = new File(root + fileName.toString());
		if (!dir.exists())
			dir.mkdirs();
		
		StringBuilder thumbFileName = new StringBuilder(fileName);
		thumbFileName.append("thumb/");
		File thumbDir = new File(root + thumbFileName.toString());
		if (!thumbDir.exists())
			thumbDir.mkdirs();
		
		String file = UUID.generator();
		fileName.append(file).append(ext);
		thumbFileName.append(file).append(ext);

		model.setName(UrlUtil.getFileName(model.getUrl()));
		model.setPath(fileName.toString());
		model.setThumbPath(thumbFileName.toString());
		return model;
	}
	
	public static enum Type
	{
		DATE, DOC
	}
	
}
